package com.gel.codegeneration.core.builder;

import cn.hutool.core.util.RuntimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @BelongsProject: code-generation-platform
 * @BelongsPackage: com.gel.codegeneration.core.builder
 * @Author: gel
 * @CreateTime: 2025-08-24  21:17
 * @Description: TODO 构建vue项目
 * @Version: 1.0
 */
@Slf4j
@Component
public class VueProjectBuilder {
    // 使用固定大小的线程池处理异步构建任务
    private static final ExecutorService EXECUTOR =  Executors.newFixedThreadPool(3);
    public CompletableFuture buildVueProjectAsync(String projectPath) {
        return CompletableFuture.supplyAsync(() -> buildProject(projectPath),EXECUTOR);
    }

    /**
     * 构建 Vue 项目
     *
     * @param projectPath 项目根目录路径
     * @return 是否构建成功
     */
    public boolean buildProject(String projectPath) {
        File projectDir = new File(projectPath);
        if (!projectDir.exists() || !projectDir.isDirectory()) {
            log.error("项目目录不存在: {}", projectPath);
            return false;
        }
        // 检查 package.json 是否存在
        File packageJson = new File(projectDir, "package.json");
        if (!packageJson.exists()) {
            log.error("package.json 文件不存在: {}", packageJson.getAbsolutePath());
            return false;
        }
        log.info("开始构建 Vue 项目: {}", projectPath);
        // 执行 npm install
        if (!executeNpmInstall(projectDir)) {
            log.error("npm install 执行失败");
            return false;
        }
        // 执行 npm run build
        if (!executeNpmBuild(projectDir)) {
            log.error("npm run build 执行失败");
            return false;
        }
        // 验证 dist 目录是否生成
        File distDir = new File(projectDir, "dist");
        if (!distDir.exists()) {
            log.error("构建完成但 dist 目录未生成: {}", distDir.getAbsolutePath());
            return false;
        }
        log.info("Vue 项目构建成功，dist 目录: {}", distDir.getAbsolutePath());
        return true;
    }


    /**
     * 执行npm install 命令
     * @param projectDir
     * @return
     */

    private  boolean executeNpmInstall(File projectDir){
        log.info("执行npm install...");
        String command=String.format(" %s install",buildCommand("npm"));
        return executeCommand(projectDir,command,300);//5分钟超时
    }
    /**
     * 执行npm build 命令
     * @param projectDir
     * @return
     */

    private  boolean executeNpmBuild(File projectDir) {
        log.info("执行npm run build...");
        String command=String.format(" %s run build",buildCommand("npm"));
        return executeCommand(projectDir,command,180);//2分钟超时
    }
    /**
     * 执行命令
     * @param workingDir 工作目录
     * @param command 命令
     * @param timeoutSeconds 超时时间
     * @return 是否成功
     */
    private boolean executeCommand(File workingDir, String command,int  timeoutSeconds){
        try{
            log.info("在目录{}中执行命令:{}",workingDir.getAbsolutePath(), command);
            String[] cmdArray = command.trim().split("\\s+");
            Process process = RuntimeUtil.exec(null, workingDir, cmdArray);
            //等待进程完成设置超时时间
            boolean completed = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
            if (!completed){
                log.error("命令执行超时({}秒)，强制终止执行", timeoutSeconds);
                process.destroyForcibly();
                return false;
            }
            int exitValue = process.exitValue();
            if(exitValue == 0){
                log.info("命令执行成功:{}", command);
                return true;
            }else {
                log.error("命令执行失败,退出码{}", exitValue);
                return false;
            }

        }catch (Exception e){
            log.error("执行命令失败：{}，错误信息：", command, e.getMessage());
            return false;
        }
    }

    private boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("windows");
    }

    private String buildCommand(String command) {
        if (isWindows()) {
            return command+".cmd";
        }
        return command;
    }
}
